﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Acoris.Parser.Aml
{
    using Acoris.Document;

    /// <summary>
    /// 表示Aml文档解析器
    /// </summary>
    public sealed class AmlParser
    {
        sealed class AmlLex : DFA<AmlLexState, AmlTokenType>
        {
            IDictionary<AmlLexState,DFAState<AmlTokenType>> _stateGraph;


            #region Protected

            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            protected override DFAState<AmlTokenType> GetStartState()
            {
                return _stateGraph[AmlLexState.EmptyState];
            }

            /// <summary>
            /// 
            /// </summary>
            protected override void InitalizeLexState()
            {
                // 这里的AnyWord使用'\0'代替
                //
                _stateGraph = InitalizeLexStateTable();


                var emptyState = this[AmlLexState.EmptyState];
                var tagOpenState = this[AmlLexState.TagOpenState];

                // 空状态的唯一后继
                // '<' -> TagOpenState
                emptyState.AddState('<', tagOpenState);

                var afterTagOpenState = this[AmlLexState.AfterTagOpenState];
                var beforeTagNameState = this[AmlLexState.BeforeTagNameState];
                var commentState = this[AmlLexState.CommentState];

                // TagOpenState
                // Anyword -> BeforeTagNameState
                // '/'  -> AfterTagOpenState
                tagOpenState.AddState('\0', beforeTagNameState);
                tagOpenState.AddState('/', afterTagOpenState);
                tagOpenState.AddState('!', commentState);

                var beforeCloseState = this[AmlLexState.BeforeCloseState];
                var beforeDeclareCloseState = this[AmlLexState.BeforeDeclareCloseState];
                var attributeNameState = this[AmlLexState.AttributeNameState];
                var textState = this[AmlLexState.TextState];

                // BeforeTagNameState
                // '\x20' -> AttributeNameState
                // '>' -> BeforeCloseState
                // '/' -> BeforeDeclareCloseState
                beforeTagNameState.AddState('\x20', attributeNameState);
                beforeTagNameState.AddState('>', textState);
                beforeTagNameState.AddState('/', beforeDeclareCloseState);

                // BeforeDeclareCloseState
                // '>'->  BeforeCloseState

                beforeDeclareCloseState.AddState('>', beforeCloseState);

                // BeforeCloseState
                // '<' -> TagOpenState
                // '\x20','\r','\n' EmptyState
                beforeCloseState.AddState('<', tagOpenState);
                beforeCloseState.AddState('\r', emptyState);
                beforeCloseState.AddState('\n', emptyState);
                beforeCloseState.AddState('\x20', emptyState);

                var afterTagNameState = this[AmlLexState.AfterTagNameState];

                // AfterTagName
                // '\0' -> AfterTagNameState            
                afterTagOpenState.AddState('\0', afterTagNameState);
                afterTagNameState.AddState('\r', afterTagNameState);
                afterTagNameState.AddState('\n', afterTagNameState);
                afterTagNameState.AddState('\x20', afterTagNameState);

                var entityState = this[AmlLexState.EntityState];

                // TextState
                // '&' -> EntityState
                // '<' -> TagOpenState
                textState.AddState('&', entityState);
                textState.AddState('<', tagOpenState);

                // AttributeNameState
                // '=' -> AttributeNameCloseState
                var attributeNameCloseState = this[AmlLexState.AttributeNameCloseState];
                attributeNameState.AddState('=', attributeNameCloseState);

                // AttributeNameCloseState
                // '"' -> AttributeValueState            
                var attributeValueState = this[AmlLexState.AttributeValueState];
                attributeNameCloseState.AddState('"', attributeValueState);

                var attributeValueCloseState = this[AmlLexState.AttributeValueCloseState];
                // AttributeValueState
                // '&' -> EntityState
                // '"' -> AttributeValueCloseState
                attributeValueState.AddState('&', entityState);
                attributeValueState.AddState('"', attributeValueCloseState);

                // AttributeValueCloseState
                // '\x20' -> AttributeNameState
                // '\r''\n' -> AttributeValueCloseState
                // '>' -> TextState
                // '/' -> BeforeDeclareCloseState
                attributeValueCloseState.AddState('\x20', attributeNameState);
                attributeValueCloseState.AddState('\r', attributeValueCloseState);
                attributeValueCloseState.AddState('\n', attributeValueCloseState);
                attributeValueCloseState.AddState('>', textState);
                attributeValueCloseState.AddState('/', beforeDeclareCloseState);

                // AfterTagNameState
                // '>' empty
                // '\r''\n''\x20' AfterTagNameState

                afterTagNameState.AddState('>', emptyState);
                afterTagNameState.AddState('\x20', afterTagNameState);
                afterTagNameState.AddState('\r', afterTagNameState);
                afterTagNameState.AddState('\n', afterTagNameState);

                // CommentState
                commentState.AddState('>', emptyState);
            }

            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            protected override IDictionary<AmlLexState, DFAState<AmlTokenType>> InitalizeLexStateTable()
            {
                return new Dictionary<AmlLexState, DFAState<AmlTokenType>>
            {
                { AmlLexState.AfterTagNameState,new AmlAfterTagNameState() },
                { AmlLexState.AfterTagOpenState,new AmlAfterTagOpenState() },
                { AmlLexState.AttributeNameCloseState,new AmlAttributeNameCloseState() },
                { AmlLexState.AttributeNameState,new AmlAttributeNameState() },
                { AmlLexState.AttributeValueState,new AmlAttributeValueState() },
                { AmlLexState.AttributeValueCloseState,new AmlAttributeValueCloseState() },
                { AmlLexState.BeforeCloseState,new AmlBeforeCloseState() },
                { AmlLexState.BeforeDeclareCloseState,new AmlBeforeDeclareCloseState() },
                { AmlLexState.BeforeTagNameState,new AmlBeforeTagNameState() },
                { AmlLexState.CDATAState,new AmlCDATAState() },
                { AmlLexState.CommentState,new AmlCommentState() },
                { AmlLexState.EmptyState,new AmlEmptyState() },
                { AmlLexState.EntityState,new AmlEntityState() },
                { AmlLexState.TagOpenState,new AmlTagOpenState() },
                { AmlLexState.TextState,new AmlTextState() },
            };
            }

            #endregion

            /// <summary>
            /// 
            /// </summary>
            /// <param name="state"></param>
            /// <returns></returns>
            public AmlLexicalAnalysisState this[AmlLexState state] {
                get {
                    if (_stateGraph.ContainsKey(state)) {
                        return (AmlLexicalAnalysisState)_stateGraph[state];
                    }
                    return null;
                }
            }
        }

        sealed class AmlSyntax
        {

        }

        public void Parse(string document)
        {
            var lex = new AmlLex();
            var syntax = new AmlSyntax();
        }
    }
}
